﻿/**
* @author erichlof /  http://github.com/erichlof
*
* A shadow Mesh that follows a shadow-casting Mesh in the scene, but is confined to a single plane.
*/

THREE.ShadowMesh = function (mesh) {

    var shadowMaterial = new THREE.MeshBasicMaterial({

        color: 0x000000,
        transparent: true,
        opacity: 0.6,
        depthWrite: false

    });

    THREE.Mesh.call(this, mesh.geometry, shadowMaterial);

    this.meshMatrix = mesh.matrixWorld;

    this.frustumCulled = false;
    this.matrixAutoUpdate = false;

};

THREE.ShadowMesh.prototype = Object.create(THREE.Mesh.prototype);
THREE.ShadowMesh.prototype.constructor = THREE.ShadowMesh;

THREE.ShadowMesh.prototype.update = function () {

    var shadowMatrix = new THREE.Matrix4();

    return function (plane, lightPosition4D) {

        // based on https://www.opengl.org/archives/resources/features/StencilTalk/tsld021.htm

        var dot = plane.normal.x * lightPosition4D.x +
			  plane.normal.y * lightPosition4D.y +
			  plane.normal.z * lightPosition4D.z +
			  -plane.constant * lightPosition4D.w;

        var sme = shadowMatrix.elements;

        sme[0] = dot - lightPosition4D.x * plane.normal.x;
        sme[4] = -lightPosition4D.x * plane.normal.y;
        sme[8] = -lightPosition4D.x * plane.normal.z;
        sme[12] = -lightPosition4D.x * -plane.constant;

        sme[1] = -lightPosition4D.y * plane.normal.x;
        sme[5] = dot - lightPosition4D.y * plane.normal.y;
        sme[9] = -lightPosition4D.y * plane.normal.z;
        sme[13] = -lightPosition4D.y * -plane.constant;

        sme[2] = -lightPosition4D.z * plane.normal.x;
        sme[6] = -lightPosition4D.z * plane.normal.y;
        sme[10] = dot - lightPosition4D.z * plane.normal.z;
        sme[14] = -lightPosition4D.z * -plane.constant;

        sme[3] = -lightPosition4D.w * plane.normal.x;
        sme[7] = -lightPosition4D.w * plane.normal.y;
        sme[11] = -lightPosition4D.w * plane.normal.z;
        sme[15] = dot - lightPosition4D.w * -plane.constant;

        this.matrix.multiplyMatrices(shadowMatrix, this.meshMatrix);

    };

} ();